#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <pthread.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/time.h>

#define SHM_SIZE (20)
#define SHM_INIT				(0X01)
#define SHM_CHANGE		(0X03)
#define NET_NAME "enp16s0f0"
#define LOG_FILE_NAME "/data/usershare/timerProc_log.txt"

#define LOG_PRINT( LINE, s) {    				\
        struct timeval tdd;       		 \
        struct timezone tz;     		\
        struct tm * t;          			\
        gettimeofday(&tdd, NULL);    		\
        t = localtime(&tdd.tv_sec); 		\
        fprintf(g_fp, "[%d-%d-%d %d:%d:%d:%06ld]>[%d] %s", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tdd.tv_usec, LINE, s);   \
}       

typedef struct
{
	int pps_src;
	int flag;			//初始化标识
}SHM_DATA_S;

int sockfd;
int g_shm_id = 0;
char * g_shm_addr = NULL;
int g_run = 1;
struct in_addr g_ipaddr;

#define PPS_SRC "/tmp/pps_src"
#define TIMER_CYCLE     (500000)      //定时器周期(纳秒)  这个是500微秒
#define GROUP_IPADDR    "225.1.1.0"       //组播地址
#define GROUP_PORT      5800            //组播端口
#define PPS_ENV         "PPS_SRC"       //pps的源环境变量
timer_t timerid;                    //定时器ID

#pragma pack(1)
typedef struct 
{
    unsigned long long tv_msec;         //毫秒
    int pps_src;                        //pps源

}NET_GROUP_DATA;

#pragma pack()

unsigned int g_count = 0;
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
FILE * g_fp = NULL;

void getEth0Ip()
{
	struct ifreq ifr;
	int sock;
	struct sockaddr_in saddr;
	strcpy(ifr.ifr_name, NET_NAME);
	sock = socket(AF_INET, SOCK_STREAM, 0);
	ioctl(sock, SIOCGIFADDR, &ifr);
	memcpy(&saddr, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
	
	g_ipaddr = saddr.sin_addr;
	//printf("1 the addr is [%s]\n", inet_ntoa(saddr.sin_addr));
    //过滤ip地址
}

int clearTimerCount()
{
    pthread_mutex_lock(&g_mutex);
    //printf("1 g_count = %d, timer = [%u]\n", g_count, g_count * TIMER_CYCLE);
    g_count = 0;
    pthread_mutex_unlock(&g_mutex);
    return 0;
}

//获取定时器的中断次数
int getTimerCount(unsigned int * current_time)
{
    pthread_mutex_lock(&g_mutex);
    //printf("2 g_count = %d, timer = [%u]\n", g_count, g_count * TIMER_CYCLE);
    *current_time = g_count;
    pthread_mutex_unlock(&g_mutex);
    return 0;
}

//定时器处理函数
void timer_handler(int signo, siginfo_t * ds, void * dd)
{
	#if 0			//只是为了打印定时器触发的时间
	static int sec =  0;
	static int count = 0;
    struct timespec ts = {0};
	(void)clock_gettime(CLOCK_MONOTONIC, &ts);
	(void)clock_gettime(CLOCK_REALTIME, &ts);
	long long milliseconds = (ts.tv_sec) + (ts.tv_nsec/1000000);
	//printf("the time is [%ld][%lu]\n", ts.tv_sec, ts.tv_nsec);
	#endif
    g_count++;
}

//PPS信号处理
void handlerMessageInfo(int sig, siginfo_t *info, void *ctx)
{
	int msg = info->si_int;
	if(msg == 10)
	{
       // LOG_PRINT( __LINE__, "recv a sig = 10\n");
       // fflush(g_fp);
		//printf(" **********recv a sig = %d data = %d data = %d *************\n", sig, info->si_value.sival_int, info->si_int);
        //判断时间数据收集标识，如果已经收集到了新的时间
        {
            //1获取秒以下的时间值
            
            //2合成时间

            //3设置系统时间

            //清除时间数据收集标识
        }
        
        
        
        //清除时间累计
        clearTimerCount();
	}
}	

//安装信号
int InstallNewSignal()
{
    struct sigaction act;
    act.sa_sigaction = handlerMessageInfo;  
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    //注册user2信号
    if(sigaction(SIGUSR2, &act, NULL) < 0) 
    {
        perror("sigaction error");
        return -1;
    }
    return 0;
}

void sigFunc(int x)
{
	//printf("the signal is [%d]\n", x);
	g_run = 0;
}

int InitBacast()
{
    int sockfd;
    struct sockaddr_in serv_addr;
    char buffer[1024] = {0};
    int addrlen = sizeof(serv_addr);
 
    // 创建套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        //printf("socket creation failed\n");
        return -1;
    }
 
    // 设置套接字选项，允许接收广播数据
    int broadcast = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) < 0) {
        //printf("setsockopt failed\n");
        return -2;
    }
 
    // 绑定套接字到特定IP地址和端口（或使用INADDR_ANY）
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    //serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 监听所有接口
    serv_addr.sin_addr = g_ipaddr;
    serv_addr.sin_port = htons(GROUP_PORT);         //的端口号
    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
       // printf("bind failed\n");
       return -2;
    }
    return 0;
}

int InitGroupBacast()
{
    
    struct sockaddr_in local_addr;
    int ttl = 10;
    int loop = 1;
    unsigned char toni;
    struct ip_mreq mreq;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("socket creation failed");
        return -1;
    }
 
    bzero(&local_addr, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //local_addr.sin_addr.s_addr = inet_aton("10.10.12");

    //getEth0Ip();
    //local_addr.sin_addr = g_ipaddr;

    local_addr.sin_port = htons(GROUP_PORT);
 
    // Bind the socket to the local address struct
    if (bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
        perror("bind failed");
        return -1;
    }
 
    // Set the time-to-live value
    if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
        perror("setsockopt for IP_MULTICAST_TTL error");
        return -1;
    }
 
    // Set the loopback mode so the process can receive its own packets
    if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) {
        perror("setsockopt for IP_MULTICAST_LOOP error");
        return -1;
    }
 
    // Set the multicast group
    bzero(&mreq, sizeof(mreq));
    //mreq.imr_multiaddr.s_addr = inet_addr(GROUP_PORT);
    mreq.imr_multiaddr.s_addr = inet_addr(GROUP_IPADDR);;
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
 
    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        perror("setsockopt for IP_ADD_MEMBERSHIP error");
       return -1;
    }
 
    return 0;
}

int writePpsSrc(FILE * fp, int src)
{
    static int old_src = 2;
    //printf("the src is [%d], old_src is [%d]\n", src, old_src);
    if(src != old_src)
    {
        
        old_src = src;
        char value = 0;

        if(src == 0)            //内部pps
        {
            value = 0;
        }
        else if(src == 1)       //外部pps
        {
            value = 1;
        }
        else        //没有pps
        {
            value = 2;
        }
        //printf("value is [%d]\n", value);
        fwrite((void*)&value, 1, 1, fp);
        fflush(fp);
        fseek(fp, 0, SEEK_SET);
    }
    return 0;
}

int initShm(void)
{
    struct timespec ts_log = {0};
	g_shm_id = shmget((key_t)6677, SHM_SIZE, IPC_CREAT|0666);
	if(g_shm_id   < 0)
	{
        struct timespec ts_log = {0};
        (void)clock_gettime(CLOCK_REALTIME, &ts_log);
		//printf("shmget error [%d]-[%s]\n", g_shm_id, strerror(errno));
        fprintf(g_fp, "[%ldus]-%s-%d shmget error [%d]-[%s]\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__, g_shm_id, strerror(errno));
		return -2;
	}
	
	//printf("shm id [%d]\n",  g_shm_id);
	if((g_shm_addr = shmat(g_shm_id, NULL, 0)) == NULL)
	{
        struct timespec ts_log = {0};
        (void)clock_gettime(CLOCK_REALTIME, &ts_log);
		fprintf(g_fp, "[%ldus]-%s-%d shmat error [%s]\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__, strerror(errno));

		return -3;
	}
	return 0;
}

int destroyShm(void)
{
		if(shmdt(g_shm_addr) < 0)
	{
		//printf("shmdt error\n");
		return -2;
	}

	//销毁共享内存
	if(shmctl(g_shm_id, IPC_RMID, NULL) < 0)
	{
		//printf("shmctl IPC_RMID error\n");
        struct timespec ts_log = {0};
        (void)clock_gettime(CLOCK_REALTIME, &ts_log);
        fprintf(g_fp, "[%ldus]-%s-%d shmctl IPC_RMID error\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000),  __FILE__, __LINE__);
		return -1;
	}
	return 0;
}

int writeShm(void * datas, int lens)
{
	if((datas == NULL) || (lens <= 0))
	{
        struct timespec ts_log = {0};
         (void)clock_gettime(CLOCK_REALTIME, &ts_log);
		//printf("parament is error \n");
        fprintf(g_fp, "[%ldus]-%s-%d parament is error \n",  (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
		return -1;
	}

	memcpy((void *)g_shm_addr,  datas, lens);
	return 0;
}

int logInitial(void)
{
    if(g_fp != NULL)
    {
        fclose(g_fp);
        g_fp = NULL;
    }
    g_fp = fopen(LOG_FILE_NAME, "a+");
    if(g_fp == NULL)
    {
        //printf("fopen return error\n");
        return -1;
    }
    return 0;
}

int main(int argc, char ** argv) 
{
    struct timespec ts_get = {0};
    struct timespec ts_curr = {0};
    int opt;
	SHM_DATA_S shm_data = {0};
	int recv_len;
    int i = 0;
    char value = 2;     //默认为没有pps的源头
    unsigned int current_irq = 0;
    int last_error_code = 0;
    struct timeval timeed;
    int ret = 0;
    struct sigevent sev;
    struct itimerspec its;
    struct sigaction sa;
    char buffer[64] = {0};        //组播数据接收buff
    NET_GROUP_DATA * timer_data = NULL;
    NET_GROUP_DATA self_timer_data;

    //加入版本查询的接口
    while ((opt = getopt(argc, argv, "v")) != -1)
    {
        switch (opt) 
        {
            case 'v': 
                printf("timerProc Version 2.00.01\n");    
            return 0;
            default :
            break;
        }
    }

    while(1)
    {
        //初始化日志打印
        ret = logInitial();
        if(ret != 0)
        {
            sleep(1);
            continue;
        }
        else
        {
            break;
        }
    }
    struct timespec ts_log = {0};
    // (void)clock_gettime(CLOCK_REALTIME, &ts_log);
    // fprintf(g_fp, "[%ldus]-%s-%d timerProc starting\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
     LOG_PRINT( __LINE__, "timerProc starting\n");
	//处理退出程序
	signal(SIGINT, sigFunc);
    
    InstallNewSignal();
    // 设置信号处理函数
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGRTMIN, &sa, NULL) == -1) 
	{
        //(void)clock_gettime(CLOCK_REALTIME, &ts_log);
        //fprintf(g_fp, "[%ldus]-%s-%d sigaction() failed\n",  (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
		 LOG_PRINT( __LINE__, "sigaction() failed\n");
         if(g_fp != NULL)
        {
            fclose(g_fp);
            g_fp = NULL;
        }
        //printf("sigaction() failed\n");
        return -1;
    }

    // 创建定时器
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = &timerid;
    if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) 
    {
        //(void)clock_gettime(CLOCK_REALTIME, &ts_log);
       // fprintf(g_fp, "[%ldus]-%s-%d timer_create() failed\n",  (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
		LOG_PRINT( __LINE__, "sigaction() failed\n");
        //printf("timer_create() failed\n");
        if(g_fp != NULL)
        {
            fclose(g_fp);
            g_fp = NULL;
        }
        return -1;
    }

    while(1)
    {
        //组播网络数据接收初始化
        ret = InitGroupBacast();
        if(ret != 0)
        {
            //printf("create group error\n");
            //(void)clock_gettime(CLOCK_REALTIME, &ts_log);
            //fprintf(g_fp, "[%ldus]-%s-%d create group error\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
		   LOG_PRINT( __LINE__, "create group error\n");
            //usleep(100);
            sleep(1);
            i++;
            if(i > 6)
            {
               return -1; 
            }
        }
        else
        {
            break;
        }
    }
	
	//共享内存初始化
	ret = initShm();	
	if(ret < 0)
	{
        //(void)clock_gettime(CLOCK_REALTIME, &ts_log);
       // fprintf(g_fp, "[%ldus]-%s-%d creater shm error\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
		 LOG_PRINT( __LINE__, "creater shm error\n");
        if(g_fp != NULL)
        {
            fclose(g_fp);
            g_fp = NULL;
        }
        
		//printf("creater shm error\n");
		return -1;
	}

	shm_data.pps_src = 2;			//写默认值2
	shm_data.flag = SHM_INIT;			//写默认值1
	writeShm(&shm_data, sizeof(SHM_DATA_S));

    // 设置定时器
    its.it_value.tv_sec = 1;            //几秒后启动定时器
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;         //定时器间隔(秒)
    its.it_interval.tv_nsec = TIMER_CYCLE;		//定时器间隔(纳秒)
   
    //printf("start timer\n");
    if (timer_settime(timerid, 0, &its, NULL) == -1) 
	{

        if(g_fp != NULL)
        {
            fclose(g_fp);
            g_fp = NULL;
        }
       // (void)clock_gettime(CLOCK_REALTIME, &ts_log);
        //fprintf(g_fp, "[%ldus]-%s-%d creater shm error\n",  (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
		LOG_PRINT( __LINE__, "creater shm error\n");
        //printf("timer_settime() failed\n");
        return -1;
    }

	//设置接收超时
	//struct timeval tv = {3, 500};		//超时为500微妙
	//setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
    //记录接收数据的时间
    (void)clock_gettime(CLOCK_MONOTONIC, &ts_get);
    fflush(g_fp);
    while (1) 
    {    
        struct sockaddr_in sender_addr;
        socklen_t sender_addr_len = sizeof(sender_addr);
        
 		if(g_run == 0)
		{
			//printf("11111 the model will quit\n");
            //(void)clock_gettime(CLOCK_REALTIME, &ts_log);
           // fprintf(g_fp, "[%ldus]-%s-%d timerProc will quit, because get Ctrl+C\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
			LOG_PRINT( __LINE__, "timerProc will quit, because get Ctrl+C\n");
			break;
		}
		
        bzero(buffer, sizeof(buffer));
        recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sender_addr, &sender_addr_len);
        if (recv_len <= 0)
        {
             (void)clock_gettime(CLOCK_MONOTONIC, &ts_curr);
             //如果时间差大于8秒，就推出
            if(ts_curr.tv_sec - ts_get.tv_sec > 7)
            {
              //  (void)clock_gettime(CLOCK_REALTIME, &ts_log);
              // fprintf(g_fp, "[%ldus]-%s-%d timerProc will out , because no get datat\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
				LOG_PRINT( __LINE__, "timerProc will out , because no get datat\n");
                //printf("timerProc will out , because no get data\n");
                //退出线程
                break;
            }
			usleep(2000);
			//printf("recv from < 0\n");
            continue;
        }

        //记录接收数据的时间
        (void)clock_gettime(CLOCK_MONOTONIC, &ts_get);

        //printf("Received packet from %s:%d:len = [%d]\n", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port), recv_len);
        

        if(recv_len != sizeof(NET_GROUP_DATA))
        {
            continue;
        }
        else
        {
            timer_data = (NET_GROUP_DATA *)buffer;
        }
        
		//去掉秒后面数据,加入本地累计的秒一下的时间
        //printf("Packet contents: [%llu], [%d]\n", timer_data->tv_msec, timer_data->pps_src);
        //写文件
       //writePpsSrc(fp, timer_data->pps_src);
		//写共享内存
		shm_data.pps_src = timer_data->pps_src;	
		shm_data.flag = SHM_CHANGE;		
		//printf("shm value is  hm_data.pps_src[%d].shm_data.flag [%d]\n",  shm_data.pps_src , shm_data.flag );
		writeShm(&shm_data, sizeof(SHM_DATA_S));
		
		if(timer_data->tv_msec != 0)
		{
        //获取到中断数
        getTimerCount(&current_irq);
        timeed.tv_sec = timer_data->tv_msec/1000;       //用接收的组播数据设置秒(传输过来的是毫秒)
	    timeed.tv_usec = current_irq/500 ;                //微秒 (中断一次是500微妙)
        ret = settimeofday(&timeed, NULL);
        //printf("settimeofday return [%d]\n", ret);
		}
		else
		{
			//printf("timer data is zero , not set time\n");
            //(void)clock_gettime(CLOCK_REALTIME, &ts_log);
           // fprintf(g_fp, "[%ldus]-%s-%d timer data is zero , not set time\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
			LOG_PRINT( __LINE__, "timer data is zero , not set time\n");
		}
    }
   // (void)clock_gettime(CLOCK_REALTIME, &ts_log);
   // fprintf(g_fp, "[%ldus]-%s-%d timerProc workes exit\n", (ts_log.tv_sec*1000000) + (ts_log.tv_nsec/1000), __FILE__, __LINE__);
	LOG_PRINT( __LINE__, "timerProc workes exit\n");
	//销毁共享内存
	destroyShm();
    if(g_fp != NULL)
    {
        fclose(g_fp);
        g_fp = NULL;
    }
    close(sockfd);              //关闭组播的接口
    pthread_mutex_destroy(&g_mutex);
    //销毁定时器
    timer_delete(timerid);
    return 0;
}
